﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using ModelingProjectLib.Interfaces;

namespace INSAwarsWPF
{
    /** Fenêtre de jeu principale */
    public partial class GameView : Window
    {
        /** ViewModel utilisée par la vue */
        public GameViewModel ViewModel { get; set; }

        /** Crée une nouvelle fenêtre de jeu pour la partie partie */
        public GameView(Partie partie)
        {
            ViewModel = new GameViewModel(this, partie);
            InitializeComponent();

            DataContext = ViewModel; // important ! (à mettre ici ou dans le xaml)
        }

        /** S'exécute à la fermeture de la fenêtre (croix ou bouton quitter)
         * Si la partie n'est pas finie, on demande une confirmation */
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (!ViewModel.IsPartieFinie)
            {
                if (MessageBox.Show("Voulez-vous vraiment quitter ?", "Confirmation", MessageBoxButton.YesNo)
                    == MessageBoxResult.Yes)
                    e.Cancel = false;
                else
                    e.Cancel = true;
            }
        }

        /** S'exécute au chargement de toutes les  listboxes d'unités dans les cases.
         * On veut donner le focus à l'unité sélectionnée dans la case sélectionéne dès le début */
        private void ListBoxUnites_Loaded(object sender, RoutedEventArgs e)
        {
            // donne le focus à l'élément sélectionné au démarrage 
            ListBox lb = sender as ListBox;
            if (lb.Items.Count > 0)
            {
                CaseViewModel selectedCase = ListBoxJeu.SelectedItem as CaseViewModel;
                UniteViewModel selectedUnite = lb.SelectedItem as UniteViewModel;

                if (selectedCase.SelectedUnite == selectedUnite)
                {
                    ListBoxItem lbi = (ListBoxItem)lb.ItemContainerGenerator.ContainerFromItem(selectedUnite);
                    Keyboard.Focus(lbi);
                }
            }
            //Keyboard.Focus(item);
        }

        /** S'exécute au chargement de la carte. Permet d'amener la fenêtre à la case qui est sélectionnée */
        private void ListBoxJeu_Loaded(object sender, RoutedEventArgs e)
        {
            // exécuté avant tous les ListBoxUnites_Loaded
            ListBoxJeu.ScrollIntoView(ViewModel.SelectedCase);
        }

        /** Méthode qui permet de donner le focus clavier à l'unité sélectionnée */
        public void focusOnSelectedUnite()
        {
            if (ListBoxJeu != null) // pour éviter le problème au démarrage quand la fenêtre n'est pas chargée
            {
                ListBoxItem selectedCaseLB = ListBoxJeu.ItemContainerGenerator.ContainerFromItem(ViewModel.SelectedCase) as ListBoxItem;
                ListBox lbUnites = FindDescendant<ListBox>(selectedCaseLB);

                ListBoxItem selectedUniteLB = lbUnites.ItemContainerGenerator.ContainerFromItem(ViewModel.SelectedCase.SelectedUnite) as ListBoxItem;
                Keyboard.Focus(selectedUniteLB);
            }
        }

        /** Méthode qui permet de parcourir les descendants d'un élément dans le XAML :
         * utile pour les descendants d'une ListBox */
        private T FindDescendant<T>(DependencyObject obj) where T : DependencyObject
        {
            // Check if this object is the specified type
            if (obj is T)
                return obj as T;

            // Check for children
            int childrenCount = VisualTreeHelper.GetChildrenCount(obj);
            if (childrenCount < 1)
                return null;

            // First check all the children
            for (int i = 0; i < childrenCount; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child is T)
                    return child as T;
            }

            // Then check the childrens children
            for (int i = 0; i < childrenCount; i++)
            {
                DependencyObject child = FindDescendant<T>(VisualTreeHelper.GetChild(obj, i));
                if (child != null && child is T)
                    return child as T;
            }

            return null;
        }


        /** Quitte la partie et la fenêtre de jeu */
        private void buttonQuitter_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        /*
        private void buttonSauvegarder_Click(object sender, RoutedEventArgs e)
        {
            //XmlSerializer serializer = new XmlSerializer(typeof(Partie));
            BinaryFormatter bf = new BinaryFormatter();

            // à mettre en variable globale
            FileStream fs = new FileStream("insawars.sav", FileMode.Create);
            bf.Serialize(fs, ViewModel);
        }
        */

        /** Lance la fin de tour et le changement de joueur puis met à jour la vue */
        private void buttonFinTour_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.Joueurs.joueurSuivant(); // les propriétés seront mises à jour automatiquement (binding)
            ViewModel.majViewChangementJoueur();
        }

        /** Crée une nouvelle ville dont on demande le nom */
        private void buttonCreerVille_Click(object sender, RoutedEventArgs e)
        {
            DemanderNomVilleView dialog = new DemanderNomVilleView("Ville-"
                + ViewModel.PartieCourante.JoueurCourant.Nom +
                "-" + (ViewModel.PartieCourante.JoueurCourant.Civilisation.ListVilles.Count + 1));

            dialog.Owner = this;
            dialog.ShowDialog();

            if (!dialog.ResultOk) return; // annulé : on ne retourne pas de ville


            // rajout d'une ville à la carte et à la liste des villes
            Ville v = ViewModel.PartieCourante.JoueurCourant.Civilisation.creerVille(ViewModel.SelectedCase.Row, ViewModel.SelectedCase.Column, dialog.ResultString);

            ViewModel.SelectedCase.ajouterVille(new VilleViewModel(ViewModel.SelectedCase, v));
            //ViewModel.majCreationVille();
            // on supprime l'enseignant
            ViewModel.SelectedCase.SelectedUnite.supprimer();
        }

        /** S'exécute quand on appuie sur une touche du clavier alors qu'une unité est sélectionnée
         * Selon la valeur de la touche (Z, Q, S ou D) on va déplacer l'unité */
        private void Unite_KeyUp(object sender, KeyEventArgs e)
        {
            if (ViewModel.SelectedCase.SelectedUnite == null)
                return;

            switch (e.Key.ToString())
            {
                case "Z":
                    ViewModel.SelectedCase.SelectedUnite.deplacerHaut();
                    break;
                case "Q":
                    ViewModel.SelectedCase.SelectedUnite.deplacerGauche();
                    break;
                case "S":
                    ViewModel.SelectedCase.SelectedUnite.deplacerBas();
                    break;
                case "D":
                    ViewModel.SelectedCase.SelectedUnite.deplacerDroite();
                    break;
                default:
                    break;
            }

            //e.Handled = true;
        }

        /** Permet d'entrer dans le mode d'extension de ville, où le joueur choisit une case où étendre sa ville */
        private void buttonEtendreVille_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.VilleAEtendre = ViewModel.SelectedCase.VilleCase;
            ViewModel.ModeExtensionVille = true;

            //ViewModel.majViewModeExtensionVille();

            MessageBox.Show("Sélectionnez une case adjacente à la ville pour l'étendre.");

            //villeAEtendre.etendre(); fait lors de la sélection de case
        }

        /** Annule le mouvement de l'unité sélectionnée */
        private void buttonAnnulMvt_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.SelectedCase.SelectedUnite.annulerMouvement();
            focusOnSelectedUnite();
        }

        /** Dans une ville, crée un directeur */
        private void creerDirecteur_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.SelectedCase.VilleCase.produireDirecteur();
        }

        /** Dans une ville, crée un enseignant */
        private void creerEnseignant_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.SelectedCase.VilleCase.produireEnseignant();
        }

        /** Dans une ville, crée un étudiant */
        private void creerEtudiant_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.SelectedCase.VilleCase.produireEtudiant();
        }

        /** Accède à l'unité suivante du joueur courant à qui il reste des points de mouvement */
        private void buttonUniteSuivante_Click(object sender, RoutedEventArgs e)
        {
            ViewModel.selectionnerUniteSuivante();
            focusOnSelectedUnite();
        }

        /** S'exécute quand une case est survolée par la souris, met à jour le contenu de la zone contextuelle */
        private void ListBoxItem_MouseEnter(object sender, MouseEventArgs e)
        {
            // on a survolé l'item sender
            ListBoxItem lbiSurvole = sender as ListBoxItem;
            CaseViewModel caseSurvolee = lbiSurvole.DataContext as CaseViewModel;

            textBlockInformations.Text = caseSurvolee.Description;
        }

        /** Met à jour la zone d'informations lors du survol du bouton créer Directeur */
        private void creerDirecteur_MouseEnter(object sender, MouseEventArgs e)
        {
            textBlockInformations.Text = "Produire un Directeur (200 Mi)\nUnité unique de civilisation. Fournit un bonus aux unités de la case.";
        }

        /** Met à jour la zone d'informations lors du survol du bouton créer Enseignant */
        private void creerEnseignant_MouseEnter(object sender, MouseEventArgs e)
        {
            textBlockInformations.Text = "Produire un Enseignant (60 Mi)\nPeut créer une ville. Ne se bat pas.";

        }

        /** Met à jour la zone d'informations lors du survol du bouton créer Etudiant */
        private void creerEtudiant_MouseEnter(object sender, MouseEventArgs e)
        {
            textBlockInformations.Text = "Produire un Etudiant (100 Mi)\nUnité de combat.";

        }
    }
}
